
#include "Util.h"

#include "Listener.h"
#include "Framework\Renderer.h"
#include "App.h"
#include "Engine.h"
#include "Sprite.h"


void	playSource();//From audio

SpriteFlags nullFlags={0,0,0};
TextureID	lightSprite;

std::map<Model*,SpriteDef::ListenerPool>	SpriteDef::drawPools;
std::vector<SpriteDef::ListenerPool*>		SpriteDef::activePools;
unsigned int								SpriteDef::activePoolTop=0;

std::map<std::string,Texture*>			SpriteDef::textureCache;
std::map<std::string,Model*>			SpriteDef::modelCache;
std::vector<SpriteDef*>					SpriteDef::spriteDefs;

void	SpriteDef::resetDrawPools(){
	for(unsigned int t=0;t<activePoolTop;t++){
		activePools[t]->clear();
	}
	activePoolTop=0;
}

void	SpriteDef::renderDrawPools(){
	for(unsigned int t=0;t<activePoolTop;t++){
		activePools[t]->pool[0]->message("drawPrep");
		activePools[t]->sendMessage("drawBatch");
	}
}

void	SpriteDef::prepModel(Renderer*	renderer,Model*	model,const Light *lights,int	lightIndex){
	renderer->setShader(shaders[0]);
	renderer->setCullFace(BACK);
	renderer->setTexture("Base", textures[0]);
	if(textures.size()>1)renderer->setTexture("Bump", textures[1]);
//	renderer->setShaderConstant3f("camPos", gApp->camPos);
//	renderer->setShaderConstant3f("lightPos", lights[lightIndex].position);
//	renderer->setShaderConstant1f("falloff", lights[lightIndex].falloff);
//	renderer->setShaderConstant1f("ambient", lightIndex? 0 : 0.1f);
	if (lightIndex > 0) renderer->setBlending(GL_ONE, GL_ONE);
	renderer->apply();
}

void	SpriteDef::addToDrawPool(Listener*	listener){
	this->drawPools[models[0]].push(listener);
}

void	SpriteDef::draw(Renderer*	renderer,const Light *lights,int	lightIndex){
	prepModel(renderer,models[0],lights,lightIndex);	
	models[0]->draw(renderer);
}


Model*	SpriteDef::getModel(const char* baseName){
	Model*	baseModel=null;
	if((baseModel=SpriteDef::findModel(baseName))==null){
		baseModel=new Model();
		bool rebuild=false;
#ifndef FORCE_REBUILD

		if(!loadModel(baseName,baseModel))rebuild=true;
#else
		if(fileExistsAndIsNewerThan(format( ASSET_PATH "%s.obj",baseName).c_str(),format( MODEL_PATH "%s.model",baseName).c_str())==false){		
			if(!loadModel(baseName,baseModel)){
				MessageBox(0,format("Couldn't load:%s. Rebuilding...",baseName).c_str(),"Rebuild",0);
				rebuild=true;
			}
		}else
			rebuild=true;
#endif
		if(rebuild && !loadOBJ(baseName,baseModel)){
			delete baseModel;
			MessageBox(0,format("Model not found:%s",baseName).c_str(),"Load Error",0);
			return null;
		}//else
		//	MessageBox(0,format("Rebuilt:%s",baseName).c_str(),"Rebuild",0);
				
		modelCache[baseName]=baseModel;
	}
	return baseModel;
}


std::vector<vec3>	LocalGeometryCache::vertexBuffer;	
std::vector<vec2>	LocalGeometryCache::uvBuffer;


//void	renderString(const char*	str,vec3&	o,vec3&	u,vec3&	v);
extern const char*	Text_chars;

void	LocalGeometryCache::renderVisible(){

	Renderer*	renderer=gApp->getRenderer();

	Listener::sendMessage("fontStartRendering");
	glBegin(GL_QUADS);
	for(unsigned int t=0;t<vertexBuffer.size();t++){
		glTexCoord2fv(uvBuffer[t]);
		glVertex3fv(vertexBuffer[t]);
	}
	std::string tmstr=format("simTime:%f",gApp->simTime);
	renderString(tmstr.c_str(),vec3(0,0,10.0f),vec3(-1,0,0),vec3(0,0,1));
	glEnd();
}

SpriteDrawPool	SpriteTrail::drawPool;
SpriteDrawPool	SpriteOverlay::drawPool;

void			SpriteOverlay::renderVisible(){
	Listener::sendMessage("fontStartRendering");
	glColor4f(0.0f,0.4f,0.8f,1.0f);
	glBegin(GL_QUADS);
	for(unsigned int i=0;i<drawPool.visibleTop;i++)
		((SpriteOverlay*)drawPool.visibleStack[i])->render(gApp->screenX*0.04f,gApp->screenY*0.04f);		
	glEnd();
}

void			SpriteTrail::renderVisible(){

	Renderer*	renderer=gApp->getRenderer();
	renderer->setTexture(TMU0, lightSprite);
	renderer->setBlending(GL_SRC_COLOR,GL_DST_COLOR );
	renderer->setMask(COLOR);
	renderer->apply();
	
	glBegin(GL_QUADS);
	for(unsigned int i=0;i<drawPool.visibleTop;i++)
		((SpriteTrail*)drawPool.visibleStack[i])->render(gApp->screenX,gApp->screenY);		
	glEnd();
}

void SpriteOverlay::render(vec3 &dx, vec3 &dy){
	if(text.length()>0){
		renderString(text.c_str(),position,dx,dy);
	}
}

void	SpriteOverlay::update(vec3	pos){
	position=pos;
}

void SpriteTrail::render(vec3 &dx, vec3 &dy){
	float scale=trailSize;
	if(buffer.size()<2)return;
	//glColor4f(1.0f,0.1f,0.1f,0.6f);//0.5f,0.5f,0.5f);
	glColor4fv(color);//(0.0f,0.4f,0.8f,0.2f);//0.5f,0.5f,0.5f);
	unsigned int sz=buffer.size();
	float ustretch=(1.0f*(1.0f-stretchLength)/(sz-1));
	for(unsigned int t=1;t<sz;t++){
		vec3&	pos1=buffer[t-1];
		vec3&	pos2=buffer[t];
		float tr1=(float)t/(sz-1);
		float tr2=(float)(t-1)/(sz-1);
		float tc1=(tr2+ustretch)*0.5f;
		float tc2=(tr1+ustretch)*0.5f;
		//float c1=1.0;//tr1;
		//float c2=1.0;//tr2;
		//glColor3f(c1,c1,c1);
		glTexCoord2f(tc1, 0);
		glVertex3fv(pos1 + (scale * dy));//(-dx + dy)));
		//glColor3f(c2,c2,c2);
		glTexCoord2f(tc2, 0);
		glVertex3fv(pos2 + (scale * dy));// ( dx + dy)));

		//glColor3f(c2,c2,c2);
		glTexCoord2f(tc2, 1);
		glVertex3fv(pos2 + (scale * -dy));// ( dx - dy)));
		//glColor3f(c1,c1,c1);
		glTexCoord2f(tc1, 1);
		glVertex3fv(pos1 + (scale * -dy));// (-dx - dy)));


		//float c1=1.0;//tr1;
		//float c2=1.0;//tr2;
		//glColor3f(c1,c1,c1);
		glTexCoord2f(tc1, 0);
		glVertex3fv(pos1 + (scale * dx));//(-dx + dy)));
		//glColor3f(c2,c2,c2);
		glTexCoord2f(tc2, 0);
		glVertex3fv(pos2 + (scale * dx));// ( dx + dy)));

		//glColor3f(c2,c2,c2);
		glTexCoord2f(tc2, 1);
		glVertex3fv(pos2 + (scale * -dx));// ( dx - dy)));
		//glColor3f(c1,c1,c1);
		glTexCoord2f(tc1, 1);
		glVertex3fv(pos1 + (scale * -dx));// (-dx - dy)));
	}
}

void	SpriteTrail::update(vec3	pos){
	const float trailSegmentLength=1.0f;
	const float maxTrailSegments=50;
	const float trailSegmentLengthSqr=(trailSegmentLength*trailSegmentLength);
	if(buffer.size()==0){buffer.push_back(pos);return;}
	vec3& top=buffer[buffer.size()-1];
	vec3 dlt=pos-top;
	float vl=length(dlt);
	if(vl<trailSegmentLength){stretchLength=vl/trailSegmentLength;return;}
	stretchLength=0.0f;
	if(buffer.size()<maxTrailSegments){buffer.push_back(pos);return;}
	for(unsigned int i=1;i<buffer.size();i++)buffer[i-1]=buffer[i];
	buffer[buffer.size()-1]=pos;
}

bool	Sprite::message(const char *msg,void*	params){
	if(msg=="update"){
		if(controller)controller->update(this);
	}else if(msg=="render"){
		selectableStack.push_back(this);
		transform.elem[0][3]=position.x;
		transform.elem[1][3]=position.y;
		transform.elem[2][3]=position.z;
		definition->addToDrawPool(this);
		
		if(controller)controller->render(this);
		/*
		static Light lights[] = {vec3(-300, 200,  100), 0.000001f,vec3( 350, -150, -100), 0.000001f,};
		transform.elem[0][3]=position.x;
		transform.elem[1][3]=position.y;
		transform.elem[2][3]=position.z;
		glPushMatrix();
		glMultTransposeMatrixf(transform);
		definition->draw(gApp->getRenderer(),lights,0);
		definition->draw(gApp->getRenderer(),lights,1);
		glPopMatrix();
		if(flags.isSelected){
			gApp->drawLight(position,gApp->screenX,gApp->screenY,200.0f);
		}*/
	}else if(msg=="drawBatch"){
		if(definition->models.size()<1||definition->models[0]==null)
			return true;
		glPushMatrix();
		glMultTransposeMatrixf(transform);
		Renderer*	renderer=gApp->getRenderer();
		//renderer->setShaderConstant4x4f("worldMatrix",transform);
		definition->models[0]->draw(renderer);
		glPopMatrix();
	}else if(msg=="drawPrep"){
		static Light lights[] = {vec3(-300, 200,  100), 0.000001f,vec3( 350, -150, -100), 0.000001f,};
		definition->prepModel(gApp->getRenderer(),definition->models[0],lights,0);
	}
	return true;
};

SpriteOverlay::SpriteOverlay(){

}

SpriteTrail::SpriteTrail(){
	stretchLength=0.0f;
	trailSize=1.0f;
	color=vec4((frand()+1.0f)*0.5f,(frand()+1.0f)*0.5f,(frand()+1.0f)*0.5f,0.8f);
}

Sprite::Sprite(){
	id=spriteBaseID++;
	idMap[id]=this;
	controller=null;
	definition=null;
	position=vec3(0,0,0);
	transform=identity4();//rotateZXY4(frand()*PI,frand()*PI,frand()*PI);
};



char*	genPath(char* pbase,char* mid,char*ext=null){
	static	char	pathBuf[1024];
	sprintf_s(pathBuf,1024,"%s%s%s",pbase,mid?mid:"",ext?ext:"");
	return &pathBuf[0];
}

ShaderID	getShader(const char*	path,const char*	defines){
	static	std::map<const char*,std::map<const char*,ShaderID>>			shaderCache;
	std::map<const char*,std::map<const char*,ShaderID>>::iterator			fnd=shaderCache.find(path);
	if(fnd==shaderCache.end() || fnd->second.find(defines)==fnd->second.end()){
		ShaderID nshader;
		std::string fpath=format("%s%s",SHADER_PATH,path);
		if((nshader = gApp->getRenderer()->addShader(fpath.c_str(),(char*)defines)) == SHADER_NONE)
			return SHADER_NONE;
		shaderCache[path][defines] = nshader;
	}
	return shaderCache[path][defines];
}

TextureID getTextureByName(char*	name,TextureFilter	filter,uint flags=0);

bool	loadSpriteDef(char*	baseName,char* shader,SpriteDef*	ndef){
	Model*	baseModel=SpriteDef::getModel(baseName);
	if(!baseModel)
		return false;
	Renderer *renderer=gApp->getRenderer();
	if (!baseModel->makeDrawable(renderer)){
		return false;
	}
	if(shader){
		static ShaderID nmlShdr;
		static bool		shdrLoaded=false;
		if(!shdrLoaded){
			if((nmlShdr = getShader(shader, "#define USE_NORMALMAP\n")) == SHADER_NONE) return false;
			shdrLoaded=true;
		}
		ndef->shaders.push_back(nmlShdr);
	}
	TextureID	aoMap,normalMap;
	char* fpath;
	TextureFilter filter=FILTER_TRILINEAR;//FILTER_POINT;//FILTER_BILINEAR
	if(fileExists(fpath=genPath(MODEL_PATH,baseName,".bmp"))&&((aoMap=getTextureByName(fpath, filter)) == TEXTURE_NONE))
		return false;
	else if(fileExists(fpath=genPath(MODEL_PATH,baseName,".png"))&&((aoMap=getTextureByName(fpath, filter)) == TEXTURE_NONE))
		return false;
	if(fileExists(fpath=genPath(MODEL_PATH,baseName,".normal.bmp"))&&((normalMap = getTextureByName(fpath, filter)) == TEXTURE_NONE))
		return false;
	else if(fileExists(fpath=genPath(MODEL_PATH,baseName,".normal.png"))&&((normalMap = getTextureByName(fpath, filter)) == TEXTURE_NONE))
		return false;
	ndef->models.push_back(baseModel);
	ndef->textures.push_back(aoMap);
	ndef->textures.push_back(normalMap);
	return true;
}

int	Sprite::spriteBaseID=1;
std::map<int,Sprite*> Sprite::idMap;

growvector<bSprite*> bSprite::displayList;
growvector<bSprite*> bSprite::activeSprites;

growvector<Sprite*> Sprite::selectableStack;

Sprite*	clickSprite;
Model*	clickModel;
vec2	lastClickUV(0,0);
int		lastClickTriangle=-1;
vec2	clickUV(0,0);
int		clickTriangleIndex=-1;
vec3	clickNormal(0,0,0);
vec3	clickPoint(0,0,0);

extern int	mapTextureDim; //Declared in APP

bool renderHexMapTexture(Renderer* renderer){
	// Setup the OpenGL viewpoint
	
	renderer->changeModelViewMatrix(identity4());
	renderer->setBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	renderer->changeProjectionMatrix(orthoMatrix(0, (float)mapTextureDim, (float)mapTextureDim,0, -1, 1, false));
	renderer->apply();
	
	glDisable(GL_TEXTURE_2D);
//	glEnable(GL_LINE_SMOOTH);
	glEnable (GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);

	if(lastClickTriangle!=clickTriangleIndex){
		lastClickTriangle=clickTriangleIndex;
		lastClickUV=clickUV;
	}

	static bool first = true;
	if(!first){
		//return true;
		glLineWidth(4.0f);
		glBegin(GL_LINES);
		//for(int t=0;t<1000;t++){
			glColor4f(0.1f,0.1f,0.1f,0.3f);
			glVertex3f(lastClickUV.x*1024.0f,lastClickUV.y*1024.0f,0);
			glVertex3f(clickUV.x*1024.0f,clickUV.y*1024.0f,0);
			lastClickUV=clickUV;
		//}
		glEnd();
		glDisable(GL_LINE_SMOOTH);
		//glEnable(GL_TEXTURE_2D);
		glColor4f(1,1,1,1);
		return true;
	}

	renderer->clearBuffers(COLOR_BUFFER | DEPTH_BUFFER, vec4(0.3f,0.3f,0.9f,1.0f));
	first=false;
	float rad=16;
	float edgeLen=sin(PI/6.0f)*2.0f*rad;
	float tileHeight=cos(PI/6.0f)*rad;
	float xstep=(rad*2.0f)+edgeLen;
	float ystep=tileHeight;
	vec3	pts[6];
	for(int t=0;t<6;t++){
		float thed=PI*2.0f*t/6.0f;
		pts[t]=vec3(sin(thed),cos(thed),0)*rad;
	}
	glBegin(GL_TRIANGLES);
	for(int ty=0;ty<80;ty++){
		for(int tx=0;tx<40;tx++){
			vec3	org;
			//glColor4f(frrand(0,1),frrand(0,1),frrand(0,1),frrand(0,1));
			const float  roundingError=0.01f;
			org.y=mapTextureDim-(float)((int)(xstep*(tx+roundingError)));
			org.x=(float)((int)(ystep*(ty+roundingError)));
			org.z=0;
			if(ty&1){//010445
				org.y+=xstep*0.5f;
				org.x+=ystep*2.0f;
			}
			glColor4f(frrand(0,1),frrand(0,1),frrand(0,1),frrand(0,1));
			for(int step=1;step<7;step++){
				vec3 pa=pts[step-1]+org;
				vec3 pb=pts[step%6]+org;
				glVertex3fv(pa);
				glVertex3fv(pb);
				glVertex3fv(org);
/*				float thed1=(step-1)*PI/3;
				float thed2=step*PI/3;
				float sa=sin(thed1)*rad;
				float ca=cos(thed1)*rad;
				float sa1=sin(thed2)*rad;
				float ca1=cos(thed2)*rad;
				glVertex3f(ox+ca,oy+sa,0);
				glVertex3f(ox+ca1,oy+sa1,0);*/
			}
		}
	}
	glEnd();
	for(int step=3;step>=1;step-=1){
		if(step==3){
			glLineWidth(2.0f);
			glColor4f(0.1f,0.1f,0.1f,0.25f);//0.25f,0.25f,0.25f,0.25f);
		}else if(step==2){
			glLineWidth(1.50f);
			glColor4f(0.1f,0.1f,0.1f,0.25f);//0.25f,0.25f,0.25f,0.25f);
		}else{
			glLineWidth(1.0f);
			glColor4f(0.1f,0.1f,0.1f,0.25);//0.25f,0.25f,0.25f,0.25f);
		}
		glBegin(GL_LINES);
		for(int ty=0;ty<80;ty++){
			for(int tx=0;tx<40;tx++){
				vec3	org;
				//glColor4f(frrand(0,1),frrand(0,1),frrand(0,1),frrand(0,1));
				const float  roundingError=0.01f;
				org.y=mapTextureDim-(float)((int)(xstep*(tx+roundingError)));
				org.x=(float)((int)(ystep*(ty+roundingError)));
				org.z=0;
				if(ty&1){//010445
					org.y+=xstep*0.5f;
					org.x+=ystep*2.0f;
				}
				for(int step=1;step<7;step++){
					vec3 pa=pts[step-1]+org;
					vec3 pb=pts[step%6]+org;
					glVertex3fv(pa);
					glVertex3fv(pb);
	/*				float thed1=(step-1)*PI/3;
					float thed2=step*PI/3;
					float sa=sin(thed1)*rad;
					float ca=cos(thed1)*rad;
					float sa1=sin(thed2)*rad;
					float ca1=cos(thed2)*rad;
					glVertex3f(ox+ca,oy+sa,0);
					glVertex3f(ox+ca1,oy+sa1,0);*/
				}
			}
		}
		glEnd();
	}
	glDisable(GL_LINE_SMOOTH);
	glEnable(GL_TEXTURE_2D);
	glColor4f(1,1,1,1);
	return true;
}



void doSpritePicking(){
	vec3 pickRay=engineGetPickRay(engineMouseX,engineMouseY);
	mat4& camModelView=gApp->camModelView;
	vec3 dx = gApp->screenX = camModelView.getRightVec();
	vec3 dy = gApp->screenY = camModelView.getUpVec();

	vec3 cp=gApp->camPos;
	vec3 camRay=pickRay;
	camRay=normalize(camRay);

	float	bestDist=10000.0f;
	static int lastBest=-1;
	Sprite*	bestSprite=null;
	int		bestHit=-1;
	for(unsigned int t=0;t<Sprite::selectableStack.size();t++){
		Sprite*	ssp=Sprite::selectableStack[t];
		ssp->flags.isSelected=0;
		vec3	ppos=ssp->position;
		float odepth=dot(ppos-cp,camRay);
		if(odepth<0.0f)continue;
		vec3 ipos=cp+(camRay*odepth);
		float dist=length(ipos-ppos); //Get distance from pick ray, to centerpoint of object projected along pick ray..
		if(dist<ssp->getRadius()){
			//Object was clicked...
			if(odepth<bestDist){
				bestDist=odepth;
				bestHit=t;
				bestSprite=ssp;
			}
		}
	}

	if(bestHit!=lastBest){
		lastBest=bestHit;
//		playSource();
	}
	if(bestSprite && bestSprite->allowRaycastGeometry()){
		bestSprite->flags.isSelected=1;
		gApp->camTargetID=bestSprite->id;

		Model*	m = bestSprite->definition->models[0];
		VertexVT*	vts=(VertexVT*)m->getVertexArray();
		int*	indices = (int*)m->getIndexArray();
		Ray		r;
		r.o=cp-bestSprite->position;
		mat4 itt=(transpose(bestSprite->transform)*1.0f);
		r.o= (itt * vec4(r.o,1.0f)).xyz();
		vec4 rd=itt * vec4(normalize(camRay),0.0f);
		r.d=rd.xyz();

		r.mint=0;
		r.maxt=10000.0f;
		int ic=m->getIndexCount();
		float bestT=10000.0f;
		int bestTI=0;
		bool gotHit=false;
		UV	 bestUV;
		vec3	bestPt;
		for(int ti=0;ti<ic;ti+=3){
			float ct;
			UV	 buv;
			VertexVT&	va=vts[indices[ti]];
			VertexVT&	vb=vts[indices[ti+1]];
			VertexVT&	vc=vts[indices[ti+2]];
			if(IntersectTriangle(r,va.vertex,vb.vertex,vc.vertex, &ct, &buv)){
				if(ct<bestT){
					bestT=ct;
					bestTI=ti;
					bestUV=buv;
					bestPt=r.o+(r.d*ct);
					gotHit=true;
				}
			}
		}
		if(gotHit){
			if(clickSprite && clickSprite!=bestSprite && gEngine->rightClicked){
				//Target clicked
				playSource();
				clickSprite->message("targetCmd",&bestSprite->id);
			}

			clickSprite=bestSprite;
			VertexVT&	va=vts[indices[bestTI]];
			VertexVT&	vb=vts[indices[bestTI+1]];
			VertexVT&	vc=vts[indices[bestTI+2]];
			clickUV=(va.texCoord*(1.0f-bestUV.u-bestUV.v))+(vb.texCoord*bestUV.u)+(vc.texCoord*bestUV.v);
			clickNormal=normalize(cross((vb.vertex-va.vertex),(vc.vertex-va.vertex)));
			clickPoint=bestPt;
			clickModel=m;
			clickTriangleIndex=bestTI;
			vec3	worldNormal=(clickSprite->transform * vec4(clickNormal,0.0f)).xyz();
			vec4	worldPt=(clickSprite->transform * vec4(clickPoint,1.0f));
			worldPt/=worldPt.w;
			vec3	wldX=normalize(cross(worldNormal,worldPt.xyz()-cp));
			vec3	wldY=cross(wldX,worldNormal);
			gApp->drawLight(worldPt.xyz()+(worldNormal*0.2f),wldX,wldY,clickSprite->getRadius()*0.25f);
		}
	}
}

void drawSelectedSprites(){	
	for(unsigned int t=0;t<Sprite::selectableStack.size();t++){
		Sprite*	ssp=Sprite::selectableStack[t];
		if(ssp->flags.isSelected){
			gApp->drawLight(ssp->position,gApp->screenX,gApp->screenY,ssp->getRadius()*1.5f);
		}
	}
}

class SpriteClassListener : public Listener
{
public:
	virtual bool	message(const char *msg=null,void*	params=null){
		if(msg=="buildSprites"){
			if ((lightSprite = gApp->getRenderer()->addTexture(TEX_PATH "particle0001.bmp", FILTER_BILINEAR)) == TEXTURE_NONE) return false;

		}else if(msg=="startRendering"){
			Sprite::resetSelection();
			
			SpriteDef::resetDrawPools();
			SpriteTrail::resetDrawPools();
			SpriteOverlay::resetDrawPools();

		}else if(msg=="renderSprites"){
			
			glPushMatrix();
			Sprite::renderAll();

			SpriteDef::renderDrawPools();

			SpriteTrail::renderVisible();

			SpriteOverlay::renderVisible();

			LocalGeometryCache::renderVisible();

		}else if(msg=="finishRendering"){
			glPopMatrix();
		}else if(msg=="drawSelectedSprites"){
			drawSelectedSprites();
		}else if(msg=="doSpritePicking"){
			doSpritePicking();
		}else if(msg=="updateSprites"){
			Sprite::updateAll();
		}else if(msg=="updateSpriteCam"){
			std::map<int,Sprite*>::iterator itor=Sprite::idMap.find(gApp->camTargetID);
			if(itor!=Sprite::idMap.end()){
				gApp->camTarget=&itor->second->transform;
			}
		}else if(msg=="renderHexMap"){
			return renderHexMapTexture((Renderer*) params);
		}
		return true;
	}
	SpriteClassListener(){
		Listener::listen(this,"buildSprites");
		Listener::listen(this,"startRendering");
		Listener::listen(this,"renderSprites");
		Listener::listen(this,"finishRendering");
		Listener::listen(this,"updateSprites");
		Listener::listen(this,"doSpritePicking");
		Listener::listen(this,"updateSpriteCam");
		Listener::listen(this,"renderHexMap");
		Listener::listen(this,"drawSelectedSprites");
	}
};

SpriteClassListener	gSpriteClassListener;
